// locutor
// (c) 2009, Normen Müller, normen.mueller@gmail.com  
// $Id: Base.scala 4 2009-11-06 19:59:06Z normen.mueller $
package locutor.parsing

import scala.util.parsing.combinator._
import scala.util.parsing.combinator.syntactical._

/** Base of locutor parsers
 * 
 * @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 * @version 0.0.1 */
trait BaseParser extends StdTokenParsers with ImplicitConversions {

  lazy val text = (ident | string)

  lazy val annotated_ident = ident ~ opt(annotation) ^^ { case id ~ as => id + ∑(as) }
  
  //@todo ident w/o an assignment to an constant is automatically handled as boolean and set to true
  lazy val annotation = "[" ~> ((ident <~ "=") ~ constant) ~ (("," ~> ((ident <~ "=") ~ constant))*) <~ "]" ^^ {
    case hd ~ tl => ((hd :: tl) map {case k ~ v => k+"="+v}) mkString ("[", ",", "]")
  }

  lazy val range = "[" ~> ( "*" ^^^ {"[*]"} | "+" ^^^ {"[+]"} | numeric ~ opt(":" ~> ("*" | numeric)) ^^ {
    case l ~ Some(r) => "["+l+":"+r+"]"
    case l ~ None    => "["+l+"]"
  }) <~ "]"

  //@todo add hexadecimals  
  lazy val constant = numeric | string | "true" | "false" | "null"

  lazy val primitives = "boolean" | "int" | "float" | "double" | "string" | "object"
  
  lazy val string = accept("string",  {case lexical.StringLit(n) => n})
  
  lazy val numeric = accept("numeric", {case lexical.NumericLit(n) => n})

  def ∑(o: Option[String]) = o match {case Some(s) => s case None => ""}
  def ∑(l: List[String]) = l match {case Nil => "" case _ => l mkString}

}
